package com.feshfans.controller.special;

import com.feshfans.bridge.RosterBridge;
import com.feshfans.control.RosterLabel;
import com.feshfans.controller.RegisteredController;
import com.feshfans.controller.StageManager;
import com.feshfans.po.User;
import com.feshfans.xmpp.client.AccountClient;
import com.feshfans.xmpp.client.ClientFactory;
import com.feshfans.xmpp.client.RoomClient;
import com.feshfans.xmpp.client.RosterClient;
import javafx.beans.value.ChangeListener;
import javafx.beans.value.ObservableValue;
import javafx.event.ActionEvent;
import javafx.fxml.FXML;
import javafx.fxml.Initializable;
import javafx.scene.control.*;
import javafx.scene.input.MouseEvent;
import javafx.scene.layout.VBox;
import org.jivesoftware.smack.SmackException;
import org.jivesoftware.smack.XMPPException;
import org.jivesoftware.smack.packet.Presence;
import org.jivesoftware.smack.roster.RosterEntry;
import org.jivesoftware.smack.util.StringUtils;
import org.jivesoftware.smackx.muc.HostedRoom;
import org.jivesoftware.smackx.muc.MultiUserChat;
import org.jivesoftware.smackx.muc.MultiUserChatException;
import org.jivesoftware.smackx.vcardtemp.packet.VCard;
import org.jxmpp.jid.BareJid;
import org.jxmpp.jid.EntityBareJid;
import org.jxmpp.jid.EntityFullJid;
import org.jxmpp.jid.parts.Resourcepart;
import org.jxmpp.stringprep.XmppStringprepException;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import java.math.RoundingMode;
import java.net.URL;
import java.util.*;

public class MainController extends RegisteredController implements Initializable {

    private static final Logger Log = LoggerFactory.getLogger(MainController.class);

    @FXML private ListView rosterList;
    @FXML private VBox vCardVBox;
    @FXML private TabPane tabPane;
    @FXML private ListView roomListView;

    private RosterBridge rosterBridge;
    private RosterClient rosterClient;
    private AccountClient accountClient;
    private RoomClient roomClient;
    private Map<EntityBareJid,MultiUserChat> multiUserChatMap = new HashMap<>();


    public MainController(){
        rosterClient = ClientFactory.getClient(ClientFactory.ClientType.Roster);
        accountClient = ClientFactory.getClient(ClientFactory.ClientType.Account);
        roomClient = RoomClient.getInstance();
        rosterBridge = RosterBridge.getInstance();
    }
    // 房间的维护

    @Override
    public void initialize(URL location, ResourceBundle resources) {
        // 添加 tab 切换的监听
        tabPane.getSelectionModel().selectedIndexProperty().addListener(new ChangeListener<Number>() {
            @Override
            public void changed(ObservableValue<? extends Number> observable, Number oldValue, Number newValue) {
                Log.info("oldValue:{},newValue:{}",oldValue,newValue);
                // 如果选中的是第2个，即群组，则加载所有房间
                if(newValue.intValue() == 1){
                    loadRoom();
                }
            }
        });

    }

    @Override
    public void onLoad(Object n) {

        loadRoster();
        loadSelfVCard();

    }

    private void loadRoom(){
        try {
            List<MultiUserChat> roomList = roomClient.loadRoom();

            for(MultiUserChat room : roomList){
                if(multiUserChatMap.containsKey(room.getRoom())){
                    continue;
                }
                if(!room.isJoined()){
                    room.join(Resourcepart.from(accountClient.getCurrentUser().getLocalpartOrNull().toString()));
                }

                Label label = new Label();
                label.setUserData(room.getRoom());

                String roomName = null;
                if(roomName == null && StringUtils.isNotEmpty(room.getSubject())){
                    roomName = room.getSubject();
                }
                if(roomName == null){
                    roomName = room.getRoom().getLocalpart().toString();
                }

                Log.info("subject:{},nickName:{},nickName2:{}",room.getSubject(),room.getNickname(),2);
                label.setText(roomName);
                roomListView.getItems().add(label);
                multiUserChatMap.put(room.getRoom(),room);
            }

        } catch (Exception e) {
            Log.error("加载房间失败,currentUser:{}",accountClient.getCurrentUser(),e);
        }
    }

    /**
     * 加载好友列表
     * 1. 获取所有好友，包括在线和离线
     * 2. 获取每个好友所有设备的出席状态
     * 3. 对好友列表重新排序，在线的好友在前，离线的好友在后
     * 4. 将好友添加到 ListView
     */
    public void loadRoster(){
        Set<RosterEntry> set = rosterClient.getRoster();
        System.out.println(rosterClient.getCurrentUser().toString());
        for(RosterEntry entry : set){
            System.out.println(entry.getJid().toString());
            // 去掉自己
            if(isSelf(entry.getJid(),rosterClient.getCurrentUser())){
                continue;
            }
            User user = new User();
            user.setJid(entry.getJid());
            user.setPresenceList(rosterClient.getPresenceByJid(user.getJid()));

            RosterLabel label = new RosterLabel();
            label.setJid(user.getJid());
            label.setText(user.toString());
            rosterList.getItems().add(label);
        }
    }

    private void loadSelfVCard(){
        try {
            VCard vCard = accountClient.getSelfVCard();
            if(vCard == null){
                return;
            }

            Label nickLabel = new Label();
            nickLabel.setText(vCard.getNickName());

            Label emailLabel = new Label();
            emailLabel.setText(vCard.getEmailHome());

            Label nameLabel = new Label();
            nameLabel.setText(vCard.getFirstName()+vCard.getMiddleName()+vCard.getLastName());

            vCardVBox.getChildren().addAll(nickLabel,nameLabel,emailLabel);
        } catch (Exception e) {
            Log.error("获取当前用户的 VCard 出错",e);
        }
        return;
    }

    /**
     * 判断用户是否是自己
     * @return
     */
    private boolean isSelf(BareJid jid, BareJid currentJid){
        String jidUser = jid.getLocalpartOrNull().toString()+"@"+jid.getDomain().toString();
        String currentJidUser = currentJid.getLocalpartOrNull().toString()+"@"+currentJid.getDomain().toString();
        return jidUser.equals(currentJidUser);
    }

    @FXML
    private void mouseClicked(MouseEvent event){
        // 如果是双击
        if(event.getClickCount()==2){
            int index = rosterList.getFocusModel().getFocusedIndex();
            // 排队选中空余地方导致的问题
            if(index<0){
                return;
            }
            RosterLabel rosterLabel = (RosterLabel) rosterList.getItems().get(index);
            BareJid jid = rosterLabel.getJid();
            StageManager.openOrGetMessageStage(jid);
        }
    }

    @FXML
    private void selectRoomClicked(MouseEvent event){
        // 如果是双击
        if(event.getClickCount()==2){
            int index = roomListView.getFocusModel().getFocusedIndex();
            // 排队选中空余地方导致的问题
            if(index<0){
                return;
            }
            Label rosterLabel = (Label)roomListView.getItems().get(index);
            EntityBareJid roomJid = (EntityBareJid) rosterLabel.getUserData();
            StageManager.openOrGetRoomStage(roomJid);
        }
    }


    @FXML
    private void addRoster(ActionEvent event){
        TextInputDialog dialog = new TextInputDialog();
        dialog.setTitle("添加好友");
        dialog.setHeaderText("请输入好友名称");
        Optional<String> result = dialog.showAndWait();
        //如果用户点击了关闭或者取消，取没有数据,直接返回
        if(!result.isPresent()){
            return;
        }
        String username = result.get();
        if(StringUtils.isEmpty(username)){
            return;
        }
        try {
            rosterClient.subscribeRoster(username);
            return;
        } catch (Exception e) {
            Log.error("发送好友请求失败，username:{}",username,e);
        }

        Alert alert = new Alert(Alert.AlertType.ERROR);
        alert.setContentText("发送好友请求失败");
        alert.show();
    }

    @FXML
    private void sendTempMessage(ActionEvent event){
        StageManager.openOrGetTempMessageStage();
    }

    /**
     * 添加房间
     * @param event
     */
    @FXML
    private void addRoomClicked(ActionEvent event){
        StageManager.openOrGetAddRoomStage();
    }

    /**
     * 处理添加好友请求
     * @param fromJid
     */
    public void processSubscribe(String fromJid){
        ChoiceDialog<SubscribeOption> choiceDialog = new ChoiceDialog();
        choiceDialog.setTitle("添加好友");
        choiceDialog.setHeaderText("添加好友确定");
        choiceDialog.setContentText(fromJid+" 请求添加好友");

        SubscribeOption yes = new SubscribeOption("yes","同意");
        SubscribeOption no = new SubscribeOption("no","拒绝");

        choiceDialog.getItems().addAll(yes,no);
        choiceDialog.setSelectedItem(yes);
        Optional<SubscribeOption> result = choiceDialog.showAndWait();
        SubscribeOption option = result.get();
        if(option==no){
            return;
        }
        try {
            rosterClient.subscribedRoster(fromJid);
            return;
        } catch (Exception e) {
            Log.error("处理好友请求出错，fromJid:{}",fromJid,e);
        }
        choiceDialog.close();
        Alert alert = new Alert(Alert.AlertType.ERROR);
        alert.setContentText("处理好友请求出错");
        alert.show();
    }

    /**
     * 处理好友出席通知
     */
    public void handlerPresence(BareJid jid, Presence presence){
        // 如果是自己出席，则直接返回，不处理
        if(isSelf(jid,rosterClient.getCurrentUser())){
            return;
        }
        User user = new User();
        user.setJid(jid);
        user.setPresenceList(presence);

        RosterLabel label = new RosterLabel();
        label.setJid(user.getJid());
        label.setText(user.toString());
        rosterList.getItems().remove(label);
        rosterList.getItems().add(label);
    }

    @Override
    public void register() {
        rosterBridge.register(this);
    }

    @Override
    public void unregister() {
        rosterBridge.unregister(this);
    }

    static class SubscribeOption{
        public String desc;
        public String value;

        public SubscribeOption(String value,String desc){
            this.value = value;
            this.desc = desc;
        }

        @Override
        public String toString() {
            return desc;
        }

        @Override
        public boolean equals(Object o) {
            if (this == o) return true;
            if (o == null || getClass() != o.getClass()) return false;
            SubscribeOption option = (SubscribeOption) o;
            return Objects.equals(value, option.value);
        }

        @Override
        public int hashCode() {
            return Objects.hash(value);
        }
    }
}
